// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "../../include/formfiller/FFL_FormFiller.h"
#include "../../include/formfiller/FFL_IFormFiller.h"
#include "../../include/formfiller/FFL_CheckBox.h"
#include "../../include/formfiller/FFL_ComboBox.h"
#include "../../include/formfiller/FFL_ListBox.h"
#include "../../include/formfiller/FFL_PushButton.h"
#include "../../include/formfiller/FFL_RadioButton.h"
#include "../../include/formfiller/FFL_TextField.h"

#define FFL_MAXLISTBOXHEIGHT		140.0f

// HHOOK CFFL_IFormFiller::m_hookSheet = NULL;
// MSG CFFL_IFormFiller::g_Msg;

/* ----------------------------- CFFL_IFormFiller ----------------------------- */

CFFL_IFormFiller::CFFL_IFormFiller(CPDFDoc_Environment* pApp) :
	m_pApp(pApp),
	m_bNotifying(FALSE)
{
}

CFFL_IFormFiller::~CFFL_IFormFiller()
{
    for (auto& it : m_Maps)
        delete it.second;
    m_Maps.clear();
}

FX_BOOL	CFFL_IFormFiller::Annot_HitTest(CPDFSDK_PageView* pPageView,CPDFSDK_Annot* pAnnot, CPDF_Point point)
{
	CPDF_Rect rc = pAnnot->GetRect();
	if(rc.Contains(point.x, point.y))
		return TRUE;
	return FALSE;
}

FX_RECT CFFL_IFormFiller::GetViewBBox(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot)
{
	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->GetViewBBox(pPageView, pAnnot);
	}
	else
	{
		ASSERT(pPageView != NULL);
		ASSERT(pAnnot != NULL);

		CPDF_Annot* pPDFAnnot = pAnnot->GetPDFAnnot();
		ASSERT(pPDFAnnot != NULL);

		CPDF_Rect rcAnnot;
		pPDFAnnot->GetRect(rcAnnot);

// 		CRect rcWin;
// 		pPageView->DocToWindow(rcAnnot, rcWin);
		CPDF_Rect rcWin = CPWL_Utils::InflateRect(rcAnnot,1);
//		rcWin.InflateRect(1, 1);

		return rcWin.GetOutterRect();
	}
}

void CFFL_IFormFiller::OnDraw(CPDFSDK_PageView* pPageView, /*HDC hDC,*/ CPDFSDK_Annot* pAnnot,
						CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device,
						/*const CRect& rcWindow,*/ FX_DWORD dwFlags)
{
	ASSERT(pPageView != NULL);
	CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;

	if (IsVisible(pWidget))
	{
		if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
		{
 			if (pFormFiller->IsValid())
 			{
				pFormFiller->OnDraw(pPageView, pAnnot, pDevice, pUser2Device, dwFlags);
				pAnnot->GetPDFPage();

				CPDFSDK_Document* pDocument = m_pApp->GetSDKDocument();
				if (pDocument->GetFocusAnnot() == pAnnot)
				{
					CPDF_Rect rcFocus = pFormFiller->GetFocusBox(pPageView);
					if (!rcFocus.IsEmpty())
					{
						CFX_PathData path;
						path.SetPointCount(5);
						path.SetPoint(0, rcFocus.left,  rcFocus.top, FXPT_MOVETO);
						path.SetPoint(1, rcFocus.left,  rcFocus.bottom, FXPT_LINETO);
						path.SetPoint(2, rcFocus.right,  rcFocus.bottom, FXPT_LINETO);
						path.SetPoint(3, rcFocus.right,  rcFocus.top, FXPT_LINETO);
						path.SetPoint(4, rcFocus.left,  rcFocus.top, FXPT_LINETO);

						CFX_GraphStateData gsd;
						gsd.SetDashCount(1);
						gsd.m_DashArray[0] = 1.0f;
						gsd.m_DashPhase = 0;
						gsd.m_LineWidth = 1.0f;
						pDevice->DrawPath(&path, pUser2Device, &gsd, 0, ArgbEncode(255,0,0,0), FXFILL_ALTERNATE);
					}
				}
				return;
			}
		}

		if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
			pFormFiller->OnDrawDeactive(pPageView, pAnnot, pDevice, pUser2Device, dwFlags);
		else
			pWidget->DrawAppearance(pDevice, pUser2Device, CPDF_Annot::Normal, NULL);

		if (!IsReadOnly(pWidget) && IsFillingAllowed(pWidget))
			pWidget->DrawShadow(pDevice, pPageView);
	}
}

void CFFL_IFormFiller::OnCreate(CPDFSDK_Annot* pAnnot)
{
	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		pFormFiller->OnCreate(pAnnot);
	}
}

void CFFL_IFormFiller::OnLoad(CPDFSDK_Annot* pAnnot)
{
	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		pFormFiller->OnLoad(pAnnot);
	}
}

void CFFL_IFormFiller::OnDelete(CPDFSDK_Annot* pAnnot)
{
	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		pFormFiller->OnDelete(pAnnot);
	}

	UnRegisterFormFiller(pAnnot);
}

void CFFL_IFormFiller::OnMouseEnter(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlag)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (!m_bNotifying)
	{
		CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
		if (pWidget->GetAAction(CPDF_AAction::CursorEnter))
		{
			m_bNotifying = TRUE;

			int nValueAge = pWidget->GetValueAge();

			pWidget->ClearAppModified();

			ASSERT(pPageView != NULL);



			PDFSDK_FieldAction fa;
			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);
			pWidget->OnAAction(CPDF_AAction::CursorEnter, fa, pPageView );
			m_bNotifying = FALSE;

			//if ( !IsValidAnnot(pPageView, pAnnot) ) return;

			if (pWidget->IsAppModified())
			{
				if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, FALSE))
				{
					pFormFiller->ResetPDFWindow(pPageView, pWidget->GetValueAge() == nValueAge);
				}
			}
		}
	}

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, TRUE))
	{
		pFormFiller->OnMouseEnter(pPageView, pAnnot);
	}
}

void CFFL_IFormFiller::OnMouseExit(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlag)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (!m_bNotifying)
	{
		CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
		if (pWidget->GetAAction(CPDF_AAction::CursorExit))
		{
			m_bNotifying = TRUE;
			pWidget->GetAppearanceAge();
			int nValueAge = pWidget->GetValueAge();
			pWidget->ClearAppModified();

			ASSERT(pPageView != NULL);



			PDFSDK_FieldAction fa;
			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);

			pWidget->OnAAction(CPDF_AAction::CursorExit, fa, pPageView);
			m_bNotifying = FALSE;

			//if (!IsValidAnnot(pPageView, pAnnot)) return;

			if (pWidget->IsAppModified())
			{
				if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, FALSE))
				{
					pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
				}
			}
		}
	}

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		pFormFiller->OnMouseExit(pPageView, pAnnot);
	}
}

FX_BOOL	CFFL_IFormFiller::OnLButtonDown(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlags, const CPDF_Point& point)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (!m_bNotifying)
	{
		CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
		if (Annot_HitTest(pPageView, pAnnot, point) && pWidget->GetAAction(CPDF_AAction::ButtonDown))
		{
			m_bNotifying = TRUE;
			pWidget->GetAppearanceAge();
			int nValueAge = pWidget->GetValueAge();
			pWidget->ClearAppModified();

			ASSERT(pPageView != NULL);



			PDFSDK_FieldAction fa;
			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlags);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlags);
			pWidget->OnAAction(CPDF_AAction::ButtonDown, fa, pPageView);
			m_bNotifying = FALSE;

			if (!IsValidAnnot(pPageView, pAnnot)) return TRUE;

			if (pWidget->IsAppModified())
			{
				if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, FALSE))
				{
					pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
				}
			}
		}
	}

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->OnLButtonDown(pPageView, pAnnot, nFlags, point);
	}

	return FALSE;
}

FX_BOOL	CFFL_IFormFiller::OnLButtonUp(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlags, const CPDF_Point& point)
{
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");
	CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
	CPDFSDK_Document* pDocument = m_pApp->GetSDKDocument();

	switch (pWidget->GetFieldType())
	{
	case FIELDTYPE_PUSHBUTTON:
	case FIELDTYPE_CHECKBOX:
	case FIELDTYPE_RADIOBUTTON:
		if (GetViewBBox(pPageView, pAnnot).Contains((int)point.x, (int)point.y))
			pDocument->SetFocusAnnot(pAnnot);
		break;
	default:
		pDocument->SetFocusAnnot(pAnnot);
		break;
	}

	FX_BOOL bRet = FALSE;

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		bRet = pFormFiller->OnLButtonUp(pPageView, pAnnot, nFlags, point);
	}

	if (pDocument->GetFocusAnnot() == pAnnot)
	{
		FX_BOOL bExit = FALSE;
		FX_BOOL bReset = FALSE;
		OnButtonUp(pWidget, pPageView, bReset, bExit,nFlags);
		if (bExit) return TRUE;
	}
	return bRet;
}

void CFFL_IFormFiller::OnButtonUp(CPDFSDK_Widget* pWidget, CPDFSDK_PageView* pPageView, FX_BOOL& bReset, FX_BOOL& bExit,FX_UINT nFlag)
{
	ASSERT(pWidget != NULL);

	if (!m_bNotifying)
	{
		if (pWidget->GetAAction(CPDF_AAction::ButtonUp))
		{
			m_bNotifying = TRUE;
			int nAge = pWidget->GetAppearanceAge();
			int nValueAge = pWidget->GetValueAge();

			ASSERT(pPageView != NULL);
// 			CReader_DocView* pDocView = pPageView->GetDocView();
// 			ASSERT(pDocView != NULL);



			PDFSDK_FieldAction fa;
			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);

			pWidget->OnAAction(CPDF_AAction::ButtonUp, fa, pPageView);
			m_bNotifying = FALSE;

			if (!IsValidAnnot(pPageView, pWidget))
			{
				bExit = TRUE;
				return;
			}

			if (nAge != pWidget->GetAppearanceAge())
			{
				if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, FALSE))
				{
					pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
				}

				bReset = TRUE;
			}
		}
	}
}

FX_BOOL	CFFL_IFormFiller::OnLButtonDblClk(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlags, const CPDF_Point& point)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->OnLButtonDblClk(pPageView, pAnnot, nFlags, point);
	}

	return FALSE;
}

FX_BOOL	CFFL_IFormFiller::OnMouseMove(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlags, const CPDF_Point& point)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	//change cursor
	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, TRUE))
	{
		return pFormFiller->OnMouseMove(pPageView, pAnnot, nFlags, point);
	}

	return FALSE;
}

FX_BOOL	CFFL_IFormFiller::OnMouseWheel(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlags, short zDelta, const CPDF_Point& point)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->OnMouseWheel(pPageView, pAnnot, nFlags, zDelta, point);
	}

	return FALSE;
}

FX_BOOL	CFFL_IFormFiller::OnRButtonDown(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlags, const CPDF_Point& point)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->OnRButtonDown(pPageView, pAnnot, nFlags, point);
	}

	return FALSE;
}

FX_BOOL	CFFL_IFormFiller::OnRButtonUp(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, FX_UINT nFlags, const CPDF_Point& point)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->OnRButtonUp(pPageView, pAnnot, nFlags, point);
	}

	return FALSE;
}

FX_BOOL	CFFL_IFormFiller::OnKeyDown(CPDFSDK_Annot* pAnnot, FX_UINT nKeyCode, FX_UINT nFlags)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->OnKeyDown(pAnnot, nKeyCode, nFlags);
	}

	return FALSE;
}

FX_BOOL	CFFL_IFormFiller::OnChar(CPDFSDK_Annot* pAnnot, FX_UINT nChar, FX_UINT nFlags)
{
	ASSERT(pAnnot != NULL);
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (nChar == FWL_VKEY_Tab) return TRUE;

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		return pFormFiller->OnChar(pAnnot, nChar, nFlags);
	}

	return FALSE;
}

FX_BOOL CFFL_IFormFiller::OnSetFocus(CPDFSDK_Annot* pAnnot,FX_UINT nFlag)
{
	if(!pAnnot) return FALSE;
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (!m_bNotifying)
	{
		CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
 		if (pWidget->GetAAction(CPDF_AAction::GetFocus))
 		{
  			m_bNotifying = TRUE;
			pWidget->GetAppearanceAge();
			int nValueAge = pWidget->GetValueAge();
 			pWidget->ClearAppModified();


 			CPDFSDK_PageView* pPageView = pAnnot->GetPageView();
 			ASSERT(pPageView != NULL);

 			PDFSDK_FieldAction fa;
			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);


 			CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, TRUE);
 			if(!pFormFiller) return FALSE;
 			pFormFiller->GetActionData(pPageView, CPDF_AAction::GetFocus, fa);

 			pWidget->OnAAction(CPDF_AAction::GetFocus, fa, pPageView);
 			m_bNotifying = FALSE;

 //			if (!IsValidAnnot(m_pApp, pDocument, pDocView, pPageView, pAnnot)) return FALSE;

 			if (pWidget->IsAppModified())
 			{
 				if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, FALSE))
 				{
 					pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
 				}
 			}
		}
	}

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, TRUE))
	{
		if (pFormFiller->OnSetFocus(pAnnot, nFlag))
		{
			return TRUE;
		}
		else
			return FALSE;
	}

	return TRUE;
}

FX_BOOL	CFFL_IFormFiller::OnKillFocus(CPDFSDK_Annot* pAnnot,FX_UINT nFlag)
{
	if(!pAnnot) return FALSE;
	ASSERT(pAnnot->GetPDFAnnot()->GetSubType() == "Widget");

	if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, FALSE))
	{
		if (pFormFiller->OnKillFocus(pAnnot, nFlag))
		{
 			if (!m_bNotifying)
 			{
 				CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
 				if (pWidget->GetAAction(CPDF_AAction::LoseFocus))
 				{
 					m_bNotifying = TRUE;
 					pWidget->ClearAppModified();

 					CPDFSDK_PageView* pPageView = pWidget->GetPageView();
 					ASSERT(pPageView != NULL);

 					PDFSDK_FieldAction fa;
					fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 					fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);

 					pFormFiller->GetActionData(pPageView, CPDF_AAction::LoseFocus, fa);

 					pWidget->OnAAction(CPDF_AAction::LoseFocus, fa, pPageView);
 					m_bNotifying = FALSE;

 				}
 			}
		}
		else
			return FALSE;
	}

	return TRUE;
}

FX_BOOL	CFFL_IFormFiller::IsVisible(CPDFSDK_Widget* pWidget)
{
	return pWidget->IsVisible();
}

FX_BOOL	CFFL_IFormFiller::IsReadOnly(CPDFSDK_Widget* pWidget)
{
	ASSERT(pWidget != NULL);

	int nFieldFlags = pWidget->GetFieldFlags();

	return (nFieldFlags & FIELDFLAG_READONLY) == FIELDFLAG_READONLY;
}

FX_BOOL	CFFL_IFormFiller::IsFillingAllowed(CPDFSDK_Widget* pWidget)
{
	ASSERT(pWidget != NULL);

	if (pWidget->GetFieldType() == FIELDTYPE_PUSHBUTTON)
		return TRUE;
 	else
 	{
 		CPDF_Page* pPage = pWidget->GetPDFPage();
 		ASSERT(pPage != NULL);

 		CPDF_Document* pDocument = pPage->m_pDocument;
 		ASSERT(pDocument != NULL);

		FX_DWORD dwPermissions = pDocument->GetUserPermissions();
 		return (dwPermissions&FPDFPERM_FILL_FORM) ||
 				(dwPermissions&FPDFPERM_ANNOT_FORM) ||
 			(dwPermissions&FPDFPERM_MODIFY);
 	}
	return TRUE;
}

CFFL_FormFiller* CFFL_IFormFiller::GetFormFiller(CPDFSDK_Annot* pAnnot, FX_BOOL bRegister)
{
    auto it = m_Maps.find(pAnnot);
    if (it != m_Maps.end())
        return it->second;

    if (!bRegister)
        return nullptr;

    CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
    int nFieldType = pWidget->GetFieldType();
    CFFL_FormFiller* pFormFiller;
    switch (nFieldType) {
        case FIELDTYPE_PUSHBUTTON:
            pFormFiller = new CFFL_PushButton(m_pApp, pWidget);
            break;
        case FIELDTYPE_CHECKBOX:
            pFormFiller = new CFFL_CheckBox(m_pApp, pWidget);
            break;
      case FIELDTYPE_RADIOBUTTON:
            pFormFiller = new CFFL_RadioButton(m_pApp, pWidget);
            break;
      case FIELDTYPE_TEXTFIELD:
            pFormFiller = new CFFL_TextField(m_pApp, pWidget);
            break;
      case FIELDTYPE_LISTBOX:
            pFormFiller = new CFFL_ListBox(m_pApp, pWidget);
            break;
      case FIELDTYPE_COMBOBOX:
            pFormFiller = new CFFL_ComboBox(m_pApp, pWidget);
            break;
      case FIELDTYPE_UNKNOWN:
      default:
            pFormFiller = nullptr;
            break;
    }

    if (!pFormFiller)
        return nullptr;

    m_Maps[pAnnot] = pFormFiller;
    return pFormFiller;
}

void CFFL_IFormFiller::RemoveFormFiller(CPDFSDK_Annot* pAnnot)
{
	if ( pAnnot != NULL )
	{
		UnRegisterFormFiller( pAnnot );
	}
}

void CFFL_IFormFiller::UnRegisterFormFiller(CPDFSDK_Annot* pAnnot)
{
    auto it = m_Maps.find(pAnnot);
    if (it == m_Maps.end())
        return;

    delete it->second;
    m_Maps.erase(it);
}

void CFFL_IFormFiller::QueryWherePopup(void* pPrivateData, FX_FLOAT fPopupMin,FX_FLOAT fPopupMax, int32_t & nRet, FX_FLOAT & fPopupRet)
{
	ASSERT(pPrivateData != NULL);

	CFFL_PrivateData* pData = (CFFL_PrivateData*)pPrivateData;




	CPDF_Rect rcPageView(0,0,0,0);
	rcPageView.right = pData->pWidget->GetPDFPage()->GetPageWidth();
	rcPageView.bottom = pData->pWidget->GetPDFPage()->GetPageHeight();
	rcPageView.Normalize();


	ASSERT(pData->pWidget != NULL);
	CPDF_Rect rcAnnot = pData->pWidget->GetRect();

	FX_FLOAT fTop = 0.0f;
	FX_FLOAT fBottom = 0.0f;

	CPDFSDK_Widget * pWidget = (CPDFSDK_Widget*)pData->pWidget;
	switch (pWidget->GetRotate() / 90)
	{
	default:
	case 0:
		fTop = rcPageView.top - rcAnnot.top;
		fBottom = rcAnnot.bottom - rcPageView.bottom;
		break;
	case 1:
		fTop = rcAnnot.left - rcPageView.left;
		fBottom = rcPageView.right - rcAnnot.right;
		break;
	case 2:
		fTop = rcAnnot.bottom - rcPageView.bottom;
		fBottom = rcPageView.top - rcAnnot.top;
		break;
	case 3:
		fTop = rcPageView.right - rcAnnot.right;
		fBottom = rcAnnot.left - rcPageView.left;
		break;
	}

	FX_FLOAT fFactHeight = 0;
	FX_BOOL bBottom = TRUE;
	FX_FLOAT fMaxListBoxHeight = 0;
	if (fPopupMax > FFL_MAXLISTBOXHEIGHT)
	{
		if (fPopupMin > FFL_MAXLISTBOXHEIGHT)
		{
			fMaxListBoxHeight = fPopupMin;
		}
		else
		{
			fMaxListBoxHeight = FFL_MAXLISTBOXHEIGHT;
		}
	}
	else
		fMaxListBoxHeight = fPopupMax;

	if (fBottom > fMaxListBoxHeight)
	{
		fFactHeight = fMaxListBoxHeight;
		bBottom = TRUE;
	}
	else
	{
		if (fTop > fMaxListBoxHeight)
		{
			fFactHeight = fMaxListBoxHeight;
			bBottom = FALSE;
		}
		else
		{
			if (fTop > fBottom)
			{
				fFactHeight = fTop;
				bBottom = FALSE;
			}
			else
			{
				fFactHeight = fBottom;
				bBottom = TRUE;
			}
		}
	}

	nRet = bBottom ? 0 : 1;
	fPopupRet = fFactHeight;
}

void CFFL_IFormFiller::OnKeyStrokeCommit(CPDFSDK_Widget* pWidget, CPDFSDK_PageView* pPageView, FX_BOOL& bRC, FX_BOOL& bExit, FX_DWORD nFlag)
{
	if (!m_bNotifying)
	{
		ASSERT(pWidget != NULL);
		if (pWidget->GetAAction(CPDF_AAction::KeyStroke))
		{
			m_bNotifying = TRUE;
			pWidget->ClearAppModified();

			ASSERT(pPageView != NULL);

			PDFSDK_FieldAction fa;
			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);
			fa.bWillCommit = TRUE;
			fa.bKeyDown = TRUE;
			fa.bRC = TRUE;

			CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, FALSE);
			ASSERT(pFormFiller != NULL);

			pFormFiller->GetActionData(pPageView, CPDF_AAction::KeyStroke, fa);
			pFormFiller->SaveState(pPageView);

			PDFSDK_FieldAction faOld = fa;
			pWidget->OnAAction(CPDF_AAction::KeyStroke, fa, pPageView);

			bRC = fa.bRC;
//			bExit = !IsValidAnnot(m_pApp, pDocument, pDocView, pPageView, pWidget);

			m_bNotifying = FALSE;
		}
	}
}

void CFFL_IFormFiller::OnValidate(CPDFSDK_Widget* pWidget, CPDFSDK_PageView* pPageView, FX_BOOL& bRC, FX_BOOL& bExit, FX_DWORD nFlag)
{
	if (!m_bNotifying)
	{
		ASSERT(pWidget != NULL);
		if (pWidget->GetAAction(CPDF_AAction::Validate))
		{
			m_bNotifying = TRUE;
			pWidget->ClearAppModified();

			ASSERT(pPageView != NULL);
// 			CReader_DocView* pDocView = pPageView->GetDocView();
// 			ASSERT(pDocView != NULL);



			PDFSDK_FieldAction fa;
			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);
			fa.bKeyDown = TRUE;
			fa.bRC = TRUE;

			CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, FALSE);
			ASSERT(pFormFiller != NULL);

			pFormFiller->GetActionData(pPageView, CPDF_AAction::Validate, fa);
			pFormFiller->SaveState(pPageView);

			PDFSDK_FieldAction faOld = fa;
			pWidget->OnAAction(CPDF_AAction::Validate, fa, pPageView);

			bRC = fa.bRC;
//			bExit = !IsValidAnnot(m_pApp, pDocument, pDocView, pPageView, pWidget);

			m_bNotifying = FALSE;
		}
	}
}

void CFFL_IFormFiller::OnCalculate(CPDFSDK_Widget* pWidget, CPDFSDK_PageView* pPageView, FX_BOOL& bExit, FX_DWORD nFlag)
{
	if (!m_bNotifying)
	{
		ASSERT(pWidget != NULL);
		ASSERT(pPageView != NULL);
// 		CReader_DocView* pDocView = pPageView->GetDocView();
// 		ASSERT(pDocView != NULL);
		CPDFSDK_Document* pDocument = pPageView->GetSDKDocument();
		ASSERT(pDocument != NULL);

		CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm();
		ASSERT(pInterForm != NULL);

		pInterForm->OnCalculate(pWidget->GetFormField());

//		bExit = !IsValidAnnot(m_pApp, pDocument, pDocView, pPageView, pWidget);

		m_bNotifying = FALSE;
	}
}

void CFFL_IFormFiller::OnFormat(CPDFSDK_Widget* pWidget, CPDFSDK_PageView* pPageView, FX_BOOL& bExit, FX_DWORD nFlag)
{
	if (!m_bNotifying)
	{
		ASSERT(pWidget != NULL);
		ASSERT(pPageView != NULL);
// 		CReader_DocView* pDocView = pPageView->GetDocView();
// 		ASSERT(pDocView != NULL);
		CPDFSDK_Document* pDocument = pPageView->GetSDKDocument();
		ASSERT(pDocument != NULL);

		CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm();
		ASSERT(pInterForm != NULL);

		FX_BOOL bFormated = FALSE;
		CFX_WideString sValue = pInterForm->OnFormat(pWidget->GetFormField(), bFormated);

//		bExit = !IsValidAnnot(m_pApp, pDocument, pDocView, pPageView, pWidget);

		if (bExit) return;

		if (bFormated)
		{
			pInterForm->ResetFieldAppearance(pWidget->GetFormField(), sValue.c_str(), TRUE);
			pInterForm->UpdateField(pWidget->GetFormField());
		}

		m_bNotifying = FALSE;
	}
}

FX_BOOL	CFFL_IFormFiller::IsValidAnnot(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot)
{

	ASSERT(pPageView != NULL);
	ASSERT(pAnnot != NULL);

	if(pPageView)
		return pPageView->IsValidAnnot(pAnnot->GetPDFAnnot());
	else
		return FALSE;
}

void CFFL_IFormFiller::OnBeforeKeyStroke(FX_BOOL bEditOrList, void* pPrivateData, int32_t nKeyCode,
											  CFX_WideString & strChange, const CFX_WideString& strChangeEx,
											  int nSelStart, int nSelEnd,
										FX_BOOL bKeyDown, FX_BOOL & bRC, FX_BOOL & bExit, FX_DWORD nFlag)
{
	ASSERT(pPrivateData != NULL);
	CFFL_PrivateData* pData = (CFFL_PrivateData*)pPrivateData;
	ASSERT(pData->pWidget != NULL);

	CFFL_FormFiller* pFormFiller = GetFormFiller(pData->pWidget, FALSE);
	ASSERT(pFormFiller != NULL);

	if (!m_bNotifying)
	{
		if (pData->pWidget->GetAAction(CPDF_AAction::KeyStroke))
		{
			m_bNotifying = TRUE;
			int nAge = pData->pWidget->GetAppearanceAge();
			int nValueAge = pData->pWidget->GetValueAge();

			ASSERT(pData->pPageView != NULL);
			CPDFSDK_Document* pDocument  = pData->pPageView->GetSDKDocument();

			PDFSDK_FieldAction fa;
 			fa.bModifier = m_pApp->FFI_IsCTRLKeyDown(nFlag);
 			fa.bShift = m_pApp->FFI_IsSHIFTKeyDown(nFlag);
			fa.sChange = strChange;
			fa.sChangeEx = strChangeEx;
			fa.bKeyDown = bKeyDown;
			fa.bWillCommit = FALSE;
			fa.bRC = TRUE;
			fa.nSelStart = nSelStart;
			fa.nSelEnd = nSelEnd;


			pFormFiller->GetActionData(pData->pPageView, CPDF_AAction::KeyStroke, fa);
			pFormFiller->SaveState(pData->pPageView);

			if (pData->pWidget->OnAAction(CPDF_AAction::KeyStroke, fa, pData->pPageView))
			{
				if (!IsValidAnnot(pData->pPageView, pData->pWidget))
				{
					bExit = TRUE;
					m_bNotifying = FALSE;
					return;
				}

				if (nAge != pData->pWidget->GetAppearanceAge())
				{
					CPWL_Wnd* pWnd = pFormFiller->ResetPDFWindow(pData->pPageView, nValueAge == pData->pWidget->GetValueAge());
					pData = (CFFL_PrivateData*)pWnd->GetAttachedData();
					bExit = TRUE;
				}

				if (fa.bRC)
				{
					pFormFiller->SetActionData(pData->pPageView, CPDF_AAction::KeyStroke, fa);
					bRC = FALSE;
				}
				else
				{
					pFormFiller->RestoreState(pData->pPageView);
					bRC = FALSE;
				}

				if (pDocument->GetFocusAnnot() != pData->pWidget)
				{
					pFormFiller->CommitData(pData->pPageView,nFlag);
					bExit = TRUE;
				}
			}
			else
			{
				if (!IsValidAnnot(pData->pPageView, pData->pWidget))
				{
					bExit = TRUE;
					m_bNotifying = FALSE;
					return;
				}
			}

			m_bNotifying = FALSE;
		}
	}
}

void	CFFL_IFormFiller::OnAfterKeyStroke(FX_BOOL bEditOrList, void* pPrivateData, FX_BOOL & bExit,FX_DWORD nFlag)
{
	ASSERT(pPrivateData != NULL);
	CFFL_PrivateData* pData = (CFFL_PrivateData*)pPrivateData;
	ASSERT(pData->pWidget != NULL);

	CFFL_FormFiller* pFormFiller = GetFormFiller(pData->pWidget, FALSE);
	ASSERT(pFormFiller != NULL);

	if (!bEditOrList)
		pFormFiller->OnKeyStroke(bExit);
}
